# 网络摄像头接口文件

import requests
import numpy as np
import cv2
from threading import Thread, Lock
import Auxiliary
import re

FrameSize = {
	'96x96': 0,
	'160x120': 1,
	'176x144': 2,
	'240x176': 3,
	'240x240': 4,
	'320x240': 5,
	'400x296': 6,
	'480x320': 7,
	'640x480': 8,
	'800x600': 9,
	'1024x768': 10,
	'1280x720': 11,
	'1280x1024': 12,
	'1600x1200': 13,
}

class Camera:
	def __init__(self, url):
		self.local = False
		if re.match(r'^https?://', url) is None:
			# 检测是否为文件名
			if re.match(r'^[a-zA-Z]:\\', url) is None:
				url = 'http://' + url
			else:
				self.local = True
		self.url = url
		self.frame = None
		self.frame_lock = Lock()
		self.thread = None
		self.running = False
		self.brightness_gamma = 1
		self.contrast = 1
		self.saturation_gamma = 1
		self.stream_boundary_0 = b'\r\n--123456789000000000000987654321\r\n'
		self.stream_boundary_1 = b'\r\n--987654321000000000000123456789\r\n'
		self.stream_normal = True

	def Start(self):
		self.running = True
		self.thread = Thread(target=self.Moniter, daemon=True)
		self.thread.start()

	def Stop(self):
		self.running = False
		self.thread.join()
	
	def GetFrame(self):
		if self.frame is None:
			return None
		self.frame_lock.acquire()
		frame = self.frame.copy()
		self.frame_lock.release()
		# 对比度调整
		if self.contrast != 1:
			frame = np.clip(self.contrast * frame, 0, 255)
			frame = np.asarray(frame,dtype=np.uint8)
		# 饱和度调整
		hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
		if self.saturation_gamma != 1:
			GammaTable = np.clip([np.round(((i / 255.0) ** self.saturation_gamma) * 255.0) for i in range(0, 256)], 0, 255)
			hsv[:,:,1] = cv2.LUT(hsv[:,:,1], GammaTable)
		# 亮度调整
		if self.brightness_gamma != 1:
			GammaTable = np.clip([np.round(((i / 255.0) ** self.brightness_gamma) * 255.0) for i in range(0, 256)], 0, 255)
			hsv[:,:,2] = cv2.LUT(hsv[:,:,2], GammaTable)
		frame = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
		return frame
	
	def SetSize(self, size):
		if isinstance(size, str):
			if size in list(FrameSize.keys()):
				size = FrameSize[size]
			else:
				return False
		if isinstance(size, int):
			result = requests.get(f'{self.url}/control?var=framesize&val={size}')
			return result.status_code == 200
			
	def SetQuality(self, value:int):
		value = 63 if value > 63 else (4 if value < 4 else value)
		return requests.get(f'{self.url}/control?var=quality&val={value}').status_code == 200

	def SetBrightness(self, value:float):
		self.brightness_gamma = value

	def SetContrast(self, value:float):
		self.contrast = value

	def SetSaturation(self, value:float):
		self.saturation_gamma = value

	def SetLedIntensity(self, value:int):
		value = 255 if value > 255 else (0 if value < 0 else value)
		return requests.get(f'{self.url}/control?var=led_intensity&val={value}').status_code == 200

	def Moniter(self):
		if self.local:
			self.frame_lock.acquire()
			self.frame = cv2.imread(self.url)
			self.frame_lock.release()
			return
		index = 0
		buffer = b''
		try:
			stream = requests.get(f'{self.url}:81/stream', stream=True, timeout=3)
			for chunk in stream.iter_content(chunk_size=1024):
				if not self.running:
					break
				if chunk == self.stream_boundary_0:
					if len(buffer) > 0:
						self.frame_lock.acquire()
						self.frame = cv2.imdecode(np.frombuffer(buffer, dtype=np.uint8), cv2.IMREAD_COLOR)
						self.frame_lock.release()
						buffer = b''
					self.stream_normal = True
					index = 0
				elif chunk == self.stream_boundary_1:
					if len(buffer) > 0:
						self.frame_lock.acquire()
						self.frame = cv2.imdecode(np.frombuffer(buffer, dtype=np.uint8), cv2.IMREAD_COLOR)
						self.frame_lock.release()
						buffer = b''
					self.stream_normal = False
					index = 0
				elif index == 1:
					header = chunk.decode('utf-8')
				else:
					buffer = buffer + chunk
				index = index + 1
		except Exception as e:
			print(e)
			# 检测到报错后重新启动（试图解决esp32网络连接不稳定问题）
			self.thread = Thread(target=self.Moniter, daemon=True)
			self.thread.start()